﻿#region 文件信息

/*----------------------------------------------------------------
//
// 文件名称：
// 文件功能描述：
// 设计要求：
//
// 文 件 名：    IWebApiService
// 创建者：      杨程
// 创建日期：	    2022/12/28 11:13:47

//----------------------------------------------------------------*/

#endregion

namespace Vampirewal.Admin.Server.ViewModels.WebApi;

/// <summary>
/// WebApi服务接口
/// </summary>
public interface IWebApiService
{
    IHost WebHost { get; }

    /// <summary>
    /// 启动WebApi
    /// </summary>
    void Start();

    /// <summary>
    /// 停止
    /// </summary>
    void Stop();

    /// <summary>
    /// 是否启动
    /// </summary>
    bool IsRuning { get; }
}

/// <summary>
/// WebApi服务
/// </summary>
public class WebApiService : IWebApiService
{
    public IHost WebHost { get; private set; }

    public bool IsRuning { get; private set; }

    public WebApiService()
    {
        IsRuning = false;

        WebHost = Host.CreateDefaultBuilder()
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseUrls($"http://127.0.0.1:7799")
                              .UseStartup<Startup>();
                })
                .ConfigureAppConfiguration(configBuilder =>
                {
                    configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                    configBuilder.AddEnvironmentVariables();
                })
                .Build();

        WebHost.Start();
        IsRuning = true;
    }

    public void Start()
    {
        try
        {
            WebHost.StartAsync();

            IsRuning = true;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public void Stop()
    {
        try
        {
            WebHost.StopAsync(TimeSpan.FromSeconds(2));
            //WebHost.Dispose();
            IsRuning = false;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Title = "Vampirewal.Admin",
                Version = "v1",
                Description = "Vampirewal.Admin服务端WebApi",
            });

            c.OperationFilter<AddResponseHeadersFilter>();
            c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
            c.OperationFilter<SecurityRequirementsOperationFilter>();

            //在header中添加token，传递到后台
            //Swagger响应头#
            //这里需要Nuget引用Swashbuckle.AspNetCore.Filters，oauth2需要写死，SecurityRequirementsOperationFilter中默认securitySchemaName = "oauth2";
            //未添加该配置时，Bearer一直无法加入到JWT发起的Http请求的头部，无论怎么请求都会是401；
            c.OperationFilter<SecurityRequirementsOperationFilter>();

            c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
            {
                Description = "JWT授权(数据将在请求头中进行传递)直接在下面框中输入Bearer {token}(注意两者之间是一个空格) \"",
                Name = "Authorization",//jwt默认的参数名称
                In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                Type = SecuritySchemeType.ApiKey
            });

            //xml注释
            var basePath = System.AppDomain.CurrentDomain.BaseDirectory;
            var xmlPath = Path.Combine(basePath, "Vampirewal.Admin.Server.ViewModels.xml");
            c.IncludeXmlComments(xmlPath);
        });

        #region 添加验证服务

        // 添加验证服务
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(o =>
        {
            o.TokenValidationParameters = new TokenValidationParameters
            {
                // 是否开启签名认证
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("VampirewalAdminServer")),
                // 发行人验证，这里要和token类中Claim类型的发行人保持一致
                ValidateIssuer = true,
                ValidIssuer = "VampirewalAdminServer",//发行人
                // 接收人验证
                ValidateAudience = true,
                ValidAudience = "VampirewalAdminClient",//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
            };
        });

        #endregion

        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(WebApiResultMiddleware));
            options.RespectBrowserAcceptHeader = true;
        });

        services.AddSchedule(options =>
        {
            options.AddJob<LogJobService>(Triggers.Daily());
        });

        // 注册 EventBus 服务
        services.AddEventBus(builder =>
        {
            // 注册 ToDo 事件订阅者
            builder.AddSubscriber<TestServer>();

            // 通过类型注册，Furion 4.2.1+ 版本
            //builder.AddSubscriber(typeof(ToDoEventSubscriber));

            // 批量注册事件订阅者
            //builder.AddSubscribers(ass1, ass2, ....);
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Vampirewal.Admin v1"));

        app.UseCors(options => options.WithOrigins("*").AllowAnyMethod());

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

        app.UseStaticFiles();
        app.UseScheduleUI();
    }
}

public class ErrorHandlingFilter : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        HandleExceptionAsync(context);
        context.ExceptionHandled = true;
    }

    private static void HandleExceptionAsync(ExceptionContext context)
    {
        var exception = context.Exception;

        if (exception is OperationCanceledException)
            SetExceptionResult(context, exception, System.Net.HttpStatusCode.NotFound);
        //else if (exception is MyUnauthorizedException)
        //    SetExceptionResult(context, exception, HttpStatusCode.Unauthorized);
        //else if (exception is MyException)
        //    SetExceptionResult(context, exception, HttpStatusCode.BadRequest);
        //else
        //    SetExceptionResult(context, exception, HttpStatusCode.InternalServerError);
    }

    private static void SetExceptionResult(
        ExceptionContext context,
        Exception exception,
        System.Net.HttpStatusCode code)
    {
        //context.Result = new JsonResult(new ApiResponse(exception))
        //{
        //    StatusCode = (int)code
        //};
    }
}